﻿using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Xml.Serialization;
using daDataLayer;

namespace danalyser.Controllers
{
    // Объекты, слои и синтаксическое дерево
    using daBase.Objects;
    using daBase.Objects.Metrics;
    using daBase.Analyser;
    using daBase.Objects.AnalysisErrors;
    using daBase.Objects.AnalysisErrors.Report;
    using daBase.Objects.Safe;
    using daSyntaxAnalyser.SyntaxTree;
    using daStaticAnalyser;
    using daStaticAnalyser.Analysers;
    using Properties;

    /// <summary>
    /// Контроллер анализа
    /// </summary>
    public class AnalysisController : BaseAnalysisController
    {
        // Список ошибок
        protected List<ParsingError> errors;

        /// <summary>
        /// Список ошибок
        /// </summary>
        public List<ParsingError> Errors { get { return errors; } }

        // Список метрик
        protected List<Metrica> metrics;

        /// <summary>
        /// Список метрик
        /// </summary>
        public List<Metrica> Metrics { get { return metrics; } }

        /// <summary>
        /// Удаление ошибки
        /// </summary>
        /// <param name="index">индекс ошибки</param>
        public void RomoveErrorAt(int index)
        {
            errors.RemoveAt(index);
        }

        /// <summary>
        /// Обработчик события - произошла ошибка
        /// </summary>
        /// <param name="sender">инициатор события</param>
        /// <param name="e">информация об ошибке</param>
        public override void ErrorOccured(object sender, ErrorArgs e)
        {
            errors.Add(e.Error);
        }

        /// <summary>
        /// Обработчик события - вычислена метрика
        /// </summary>
        /// <param name="sender">инициатор события</param>
        /// <param name="e">информация о метрике</param>
        public override void MetricaCalculated(object sender, MetricaArgs e)
        {
            if (!metrics.Exists(s => (s.File == e.Metric.File)
                                    && (s.Name == e.Metric.Name)
                                    && (s.Value == e.Metric.Value)
                                    && (s.Object == e.Metric.Object)
                                    && (s.Line == e.Metric.Line)))
            {
                metrics.Add(e.Metric);
            }
        }

        /// <summary>
        /// Событие "изменилась стадия анализа"
        /// </summary>
        public event EventHandler<MessageArgs> StageChangedEvent;

        /// <summary>
        /// Обработчик события "изменилась стадия анализа"
        /// </summary>
        /// <param name="sender">инициатор события</param>
        /// <param name="e">информация о стадии анализа</param>
        private void StageChanged(object sender, MessageArgs e)
        {
            if (StageChangedEvent != null)
                StageChangedEvent(sender, e);
        }

        // Одиночка
        private static AnalysisController instance;

        /// <summary>
        /// Статические анализаторы
        /// </summary>
        public List<Analyser> Analysers { get { return StaticAnalyserController.Instance.Analysers; } }

        // Профиль
        private string profile;

        /// <summary>
        /// Профиль
        /// </summary>
        public string Profile { get { return profile; } }

        /// <summary>
        /// Загрузка всех анализаторов
        /// </summary>
        public void LoadAnalysers()
        {
            string directory = string.Format("{0}\\profiles\\{1}", FileController.Instance.StartupPath, profile);
            SafeFile.CreateDirectory(directory);
            string FileName;
            foreach (Analyser analyser in StaticAnalyserController.Instance.Analysers)
            {
                FileName = string.Format("{0}\\{1}.xml", directory, analyser.GetType().Name);
                if (File.Exists(FileName))
                    analyser.Load(FileName);
                else 
                    analyser.Reset();
            }
        }

        /// <summary>
        /// Сохранение всех анализаторов
        /// </summary>
        public void SaveAnalysers()
        {
            string directory = string.Format("{0}\\profiles\\{1}", FileController.Instance.StartupPath, profile);
            SafeFile.CreateDirectory(directory);
            foreach (Analyser analyser in StaticAnalyserController.Instance.Analysers)
                analyser.Save(string.Format("{0}\\{1}.xml", directory, analyser.GetType().Name));
        }

        /// <summary>
        /// Загрузка профиля
        /// </summary>
        public void LoadProfile()
        {
            try
            {
                profile = Settings.Default.Profile;
                if ((profile == null) || (profile == string.Empty))
                    profile = "default";
            }
            catch
            {
                profile = "defaut";
            }
            LoadAnalysers();
        }

        /// <summary>
        /// Сохранение профиля
        /// </summary>
        /// <param name="Profile">профиль</param>
        public void SaveProfile(string Profile)
        {
            try
            {
                Settings.Default.Profile = Profile;
                Settings.Default.Save();
                profile = Profile;
                LoadAnalysers();
            }
            catch { }
        }

        /// <summary>
        /// Конструктор
        /// </summary>
        public AnalysisController()
        {
            errors = new List<ParsingError>();
            metrics = new List<Metrica>();
            StaticAnalyserController.Instance.MetricaCalculatedEvent += new EventHandler<MetricaArgs>(MetricaCalculated);
            StaticAnalyserController.Instance.ErrorOccuredEvent += new EventHandler<ErrorArgs>(ErrorOccured);
            StaticAnalyserController.Instance.StageChangedEvent += new EventHandler<MessageArgs>(StageChanged);
            LoadProfile();
        }

        /// <summary>
        /// Единственный экземпляр контроллера
        /// </summary>
        public static AnalysisController Instance
        {
            get
            {
                if (instance == null)
                    instance = new AnalysisController();
                return instance;
            }
        }

        /// <summary>
        /// Экспорт списка ошибок
        /// </summary>
        /// <param name="filename">имя файла для экспорта</param>
        /// <returns>результат экспорта</returns>
        public void Export(string filename)
        {
            XmlReport report = new XmlReport();
            foreach (ParsingError e in errors)
                report.Errors.Add(new SerializableError(e));
            XmlSerializer xmlfile = new XmlSerializer(typeof(XmlReport));
            FileStream file = new FileStream(filename, FileMode.Create, FileAccess.Write, FileShare.Read);
            xmlfile.Serialize(file, report);
            file.Close();
        }

        /// <summary>
        /// Анализ
        /// </summary>
        /// <param name="loadIfNeed">анализировать подключенные модули, даже если их нет в списке анализа</param>
        /// <param name="saveFormattedTo">путь для сохранения форматированного кода</param>
        public void Analyse(bool loadIfNeed, string saveFormattedTo)
        {
            errors.Clear();
            metrics.Clear();
            List<FileElement> roots = StaticAnalyserController.Instance.Analyse(FileController.Instance.FileNames, loadIfNeed);
            if (saveFormattedTo != string.Empty)
                foreach (FileElement root in roots)
                    root.SaveTo(saveFormattedTo);
        }
    }
}
